\section{能显示函数调用关系的ucore}\label{ux80fdux663eux793aux51fdux6570ux8c03ux7528ux5173ux7cfbux7684ucore}

操作系统中存在很多函数，通过函数间的调用来完成各种功能。在操作系统运行过程中，维持函数之间的调用关系，以及函数内部的局部变量是栈（stack）的基本功能。我们需要能够理解在操作系统中栈的实现细节和功能，这样能够更好地理解操作系统中函数如何相互调用，发现可能存在的问题。

\subsection{实验目标}\label{ux5b9eux9a8cux76eeux6807}

为了理解操作系统中的函数调用关系、传递参数和函数局部变量，我们设计了proj3.1，在ucore中增加了一个monitor子功能模块，能够分析出ucore在执行过程中的函数调用关系和函数传递的参数。通过分析proj3.1的实现，读者可了解基本栈结构，栈处理流程，GCC编译器的参数传递约定和构建函数调用关系的具体实现。

\subsection{proj3.1概述}\label{proj3.1ux6982ux8ff0}

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
  实现描述\\
  proj3.1建立在proj3的基础上，通过增加了一个monitor功能子模块，实现了一个能显示函数调用关系的ucore。简单地说proj3.1根据GCC生成的栈构建代码、函数参数压栈约定和实际函数调用过程中的栈结构内存空间，分析并显示函数调用关系。具体完成此工作的是print\_stackframe函数。
\item
  项目组成\\
  proj3.1整体目录结构中新增加的主要内容如下所示： proj3.1 \textbar{}--
  kern \textbar{} \textbar{}-- debug \textbar{} \textbar{} \textbar{}--
  assert.h \textbar{} \textbar{} \textbar{}-- kdebug.c \textbar{}
  \textbar{} \textbar{}-- kdebug.h \textbar{} \textbar{} \textbar{}--
  monitor.c \textbar{} \textbar{} \textbar{}-- monitor.h \textbar{}
  \textbar{} \textbar{}-- panic.c \textbar{} \textbar{}
  \lstinline!-- stab.h     |   |-- driver     |   |!-- kbdreg.h
  \textbar{} \textbar{}-- init \textbar{} \textbar{}
  \lstinline!-- init.c     |   |-- libs     |   |   |-- readline.c     |   |!--
  stdio.c \textbar{} \lstinline!-- trap     |!-- trap.h \textbar{}--
  Makefile `-- tools \textbar{}-- kernel.ld \ldots{}\ldots{}
  proj3.1是基于proj3进一步扩展完成的。相对于proj3，一共增加了10个文件，主要集中在debug目录下，这一个比较大的跨越。不过仔细看来主要增加和修改的文件不多，具体新增内容如下所示：

  \begin{itemize}
  \item
    kern/debug/monitor.{[}ch{]}：监视系统运行的monitor交互子模块
  \item
    kern/debug/debug.{[}ch{]}：实现内存地址到函数名的映射和分析显示函数调用关系；
  \item
    kern/libs/readline.c：实现monitor的接收字符输入的功能；
  \item
    kern/driver/kbdreg.h：定义了键盘的键值；
  \item
    kern/trap/trap.h：为了向后兼容中断的处理，先在此处写了一个空的trapframe结构；
  \item
    tools/kernel.ld：指导ld工具软件链接各个.o目标文件形成ucore的kernel的链接脚本；
  \end{itemize}
\item
  编译运行 编译并运行proj3.1的命令如下： cd proj3.1 make make qemu

  当``K\textgreater{}''提示符出现后，可以敲入``help''字符串，可以看到当前的monitor有三个命令可以输入：help、kerninfo、backtrace。我们敲入``backtrace''字符串，则可以得到如下显示界面：

\begin{lstlisting}
(THU.CST) os is loading ...

Welcome to the kernel debug monitor!!
Type 'help' for a list of commands.
K> help
help - Display this list of commands.
kerninfo - Display information about the kernel.
backtrace - Print backtrace of stack frame.
K> backtrace
ebp:0x00007b08 eip:0x0010073a args:0x00010094 0x00000000 0x00007b88 0x00100985 
    kern/debug/kdebug.c:216: print_stackframe+25
ebp:0x00007b18 eip:0x00100a76 args:0x00000000 0x00007b3c 0x00000000 0x0000000a 
    kern/debug/monitor.c:94: mon_backtrace+11
ebp:0x00007b88 eip:0x00100985 args:0x00108560 0x00000000 0x00007bb8 0x0010124c 
    kern/debug/monitor.c:55: runcmd+135
ebp:0x00007bb8 eip:0x001009f8 args:0x00000000 0x00101ef0 0x0000065c 0x00000000 
    kern/debug/monitor.c:70: monitor+75
ebp:0x00007be8 eip:0x00100059 args:0x00000000 0x00000000 0x00000000 0x00007c4f 
    kern/init/init.c:22: kern_init+89
ebp:0x00007bf8 eip:0x00007d5b args:0xc031fcfa 0xc08ed88e 0x64e4d08e 0xfa7502a8
\end{lstlisting}

  通过上图可以看到monitor能够把当前的函数调用关系给显示出来，而且不仅仅给出函数调用返回处的eip地址，还显示出了在实际源代码处的文件名和行号。如果ucore在执行过程中由于某种异常错误激发monitor执行（以后有这样的实验），我们就可以很容易找到问题出现在什么地方了。下面我们将从栈的基本概念、栈结构和栈处理过程等方面来分析上图中背后的东西。
\end{enumerate}
